/*->c.vtselect */

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <ctype.h>
#include <time.h>

#include "h.os"
#include "h.wimp"
#include "h.bbc"
#include "h.flex"
#include "h.akbd"


#include "h.wos"
#include "h.main"
#include "h.ram"
#include "h.file"
#include "h.mym"




#include "h.def"


#include "h.term"
#include "h.key"

#include "h.vtlo"
#include "h.vtdef"
#include "h.vtscr"
#include "h.vtcol"
#include "h.vtkey"
#include "h.vtfile"
#include "h.vtprint"

#include "h.vtwimp"

#include "h.vtselect"


/***************************************************************************/
/*
    Code to handle select zones in VT terminals
*/
/*****************************************************************************/


/* mouse coordinates in terminal buffer */ 

int mttyx;
int mttyy;


static int zlx; 
static int zly;
static int zhx;
static int zhy;
static int zfx;     /* fixed point that drag started from */
static int zfy;



void vtsetxy(void)
{ 
 tline * lp;

 getpointer();

 mttyx=(mousex-vtbx)/TTDX;
 mttyy=(-tscrolly+vty1-mousey-deltay)/TTDY;

 if(mttyx<0)         mttyx=0;
 if(mttyx>=width)    mttyx=width-1;
 if(mttyy<0)         mttyy=0;
 if(mttyy>=buffsize) mttyy=buffsize-1;

 lp=vtindex(mttyy);

 if(lp->attr) mttyx=mttyx>>1;
}





/* invert a block in the buffer */


void zpaint(int fx,int fy,int tx,int ty,int scr)
{
 int x; 
 int y;
 int lox;
 int hix;

 tline * lp;
 int     loc;
 int   * data;

 for(y=fy;y<=ty;y++)
 {
  if(y==fy) lox=fx;
  else      lox=0;

  if(y==ty) hix=tx;
  else      hix=width-1;

  lp=vtindex(y);
  loc=lp->loc;

  data=(int *)(linedata+loc);

  for(x=lox;x<=hix;x++)
  {
   data[x]=((data[x] >> 8) & 0xFF0000) ^ data[x]; 
  }
  if(scr) vtredrawlo(lp,lox,hix);
 }
}



void zless(int x,int y,int * rx,int * ry)
{
 if(x==0)
 {
  *rx=width-1;
  *ry=y-1;
 }
 else
 {
  *rx=x-1;
  *ry=y;
 }
}


void zplus(int x,int y,int * rx,int * ry)
{
 if(++x>=width)
 {
  *rx=0;
  *ry=y+1;
 }
 else
 {
  *rx=x;
  *ry=y;
 }
}



void makezhfixed(void)
{
 int tempx;
 int tempy;

 zplus(zfx,zfy,&tempx,&tempy);
 zpaint(tempx,tempy,zhx,zhy,1);

 zhx=zfx;
 zhy=zfy;
}



void makezlfixed(void)
{
 int tempx;
 int tempy;

 zless(zfx,zfy,&tempx,&tempy);
 zpaint(zlx,zly,tempx,tempy,1);

 zlx=zfx;
 zly=zfy;
}



void paintzone(int newx,int newy,int adjust)
{
 int tempx;
 int tempy;
 int midy=(zhy+zly)>>1;
 int midx=(zhx+zlx)>>1;  
                                                         /* no change */

 if((newx==zhx && newy==zhy) && (newx==zlx && newy==zly))    return;


 if(newy<zly || (newy==zly && newx<zlx))             /* extending upwards */
 {
  if(zlx==zfx && zly==zfy && !adjust) makezhfixed(); 
  zless(zlx,zly,&tempx,&tempy);
  zpaint(newx,newy,tempx,tempy,1);
  zlx=newx;
  zly=newy;
 }
 else                                                /* extending down */
 if(newy>zhy || (newy==zhy && newx>zhx))
 {
  if(zhx==zfx && zhy==zfy && !adjust) makezlfixed();
  zplus(zhx,zhy,&tempx,&tempy);
  zpaint(tempx,tempy,newx,newy,1);
  zhx=newx;
  zhy=newy;
 }
 else                                                /* shrink bottom */
 if(
    (zfx==zlx && zfy==zly && !adjust) ||
    ((newy>midy || (newy==midy && newx>midx)) && adjust)
   )
 {
  zplus(newx,newy,&tempx,&tempy);
  zpaint(tempx,tempy,zhx,zhy,1);
  zhx=newx;
  zhy=newy;
 }
 else                                               /* shrink top */
 if(
    (zfx==zhx && zfy==zhy && !adjust) ||
    ((newy<midy || (newy==midy && newx<=midx)) && adjust)
   )
 {
  zless(newx,newy,&tempx,&tempy);
  zpaint(zlx,zly,tempx,tempy,1);
  zlx=newx;
  zly=newy;
 }
}



void clearzone(void)
{
 if(vtselect)
 {
  zpaint(zlx,zly,zhx,zhy,1);
  vtselect=0;
 }
}


/* used to remove marking from data, temporarily */

static void togglezone(void)
{
 if(vtselect)
 {
  zpaint(zlx,zly,zhx,zhy,0);
 }
}



#define VTPASTECHUNK 0x100


void vtpastebyte(int byte)
{
 if(!vtpastebuff)
 {
  flex_alloc((flex_ptr)&vtpastebuff,VTPASTECHUNK);
  vtpastebufflen=0;
 }
 else
  flex_chunk((flex_ptr)&vtpastebuff,vtpastebufflen+1,VTPASTECHUNK);

 vtpastebuff[vtpastebufflen++]=byte;
}


void vttrashpastebuff(void)
{
 if(vtpastebuff) flex_free((flex_ptr)&vtpastebuff);
}



void sendzone(int copy)
{
 int lox;
 int hix;
 int x;
 int y;
 int ch;

 tline * lp;
 int     loc;
 int   * data;

 vtremzone();

 if(copy) vttrashpastebuff();

 for(y=zly;y<=zhy;y++)
 {
  lp=vtindex(y);
  loc=lp->loc;

  data=(int *)(linedata+loc);

  if(y==zly) lox=zlx;
  else       lox=0;

  if(y==zhy) hix=zhx;
  else       hix=width;

  if(zhy!=zly)                     /* strip trailing spaces */
  {
   x=hix;
   while(x)
   {
    if((data[x] & 0xFF)==32)
    {
     hix--;
     if(hix<0) hix=0;
     x=hix;
    }
    else break;
   }
  }

  for(x=lox;x<=hix;x++)
  {
   ch=data[x] & 0xFF;
   if(ch>=32)
   {
    if(copy) vtpastebyte(ch);
    else     vtintkey(ch);
   }
  }

  if(zhy!=zly)
  {
   if(copy) vtpastebyte(CR);
   else     vtintkey(CR);
  }
 }
}



void vtpastezone(void)
{
 int i;

 if(vtpastebuff && !vtselect)
 {
  for(i=0;i<vtpastebufflen;i++) vtintkey(vtpastebuff[i]);
 }
}



void printzone(void)
{
 togglezone();
 printchunk(zlx,zly,zhx,zhy);
 togglezone();
}


int savezone(char * filename)
{
 int code;
 togglezone();
 code=savechunk(zlx,zly,zhx,zhy,filename);
 togglezone();
 return(code);
}



void spoolzone(void)
{
 togglezone();
 savechunk2(zlx,zly,zhx,zhy,spfp);
 togglezone();
}


void vtselectcopy(int fp)
{
 if(vtselect) sendzone(1);
 fp=fp;
}

void vtselectpaste(int fp)
{
 vtpastezone();
 fp=fp;
}

void vtselectprint(int fp)
{
 if(vtselect) printzone();
 fp=fp;
}

void vtselectsend(int fp)
{
 if(vtselect) sendzone(0);
 fp=fp;
}

void vtselectspool(int fp)
{
 if(vtselect) spoolzone();
 fp=fp;
}




#define DMFRAC 16


void scrollwindow(int * oscx,int * oscy)
{
 int wwidth;
 int wwheight;
 int margin;

 getw(whandle[VTERM]);

 *oscx=scx;
 *oscy=scy=tscrolly;

 wwidth=x1-x0;
 wwheight=y1-y0;

 margin=wwidth/DMFRAC;
 if(mousex<(x0+margin)) scx-=2*(x0+margin-mousex);
 if(mousex>(x1-margin)) scx+=2*(mousex-x1+margin);

 margin=wwheight/DMFRAC;
 if(mousey>(y1 /* -margin */)) scy+=2*(mousey-y1+margin);
 if(mousey<(y0 /* +margin */)) scy-=2*(y0+margin-mousey);

 if(scx<0) scx=0;
 if(scx>(width*TTDX-wwidth)) scx=(width*TTDX-wwidth);

 if(scy>0) scy=0;
 if(scy<(-buffsize*TTDY+wwheight)) scy=-buffsize*TTDY+wwheight;
}







void vtsetupdrag(void)
{
 wimp_dragstr drg;

 drg.type=7;

 geto(whandle[VTERM]);
 drg.parent.y0=oy0;
 drg.parent.y1=oy1;
 drg.parent.x0=ox0;
 drg.parent.x1=ox1+vscrlbar;


 drg.box.x0=mousex;
 drg.box.x1=mousex;
 drg.box.y0=mousey;
 drg.box.y1=mousey;

 wimp_drag_box(&drg);

 startdrag(VTDRAG,whandle[VTERM]);
}







/* called whilst VT drag is going on */

void vtdragzero(void)
{
 int oscx;
 int oscy;

 vtsetxy();

 paintzone(mttyx,mttyy,0);
 if(vtpendredraw)
 {
  vtdoredraw();
  vtpendredraw=0;
 }

 scrollwindow(&oscx,&oscy);

 if(oscx!=scx || oscy!=scy) 
 {
  vtgoffset(scx,scy);
  getw(whandle[VTERM]);
  oscx=oscx-scx;
  oscy=oscy-tscrolly;

  if(oscx || oscy) vtsetupdrag();
 }
}




void vtstartzone(void)
{
 vtsetxy();

 zlx=mttyx;
 zhx=mttyx;
 zfx=mttyx;
 zly=mttyy;
 zhy=mttyy;
 zfy=mttyy;

 zpaint(zlx,zly,zhx,zhy,1);
 vtselect=1;
 terminalmode=TMODENUL;
}



void vtremzone(void)
{
 if(vtselect)
 {
  clearzone();
  terminalmode=TMODEVT;
 }
}




/* called by a drag on the main VT window */

void vtstartdrag(void)
{
 vtremzone();
 vtsetxy();

 if(((mttyy-tops)==24) && vtheight==25 && vtstatus!=VTSTHOST) return;

 vtsetupdrag();
 vtstartzone();
}




void vtscleartab(void)
{
 if(vtstatus==VTSTTABS)
 {
  tabs[mttyx]=0;
  vtrefreshstatus();
 }
}


void vtssettab(void)
{
 if(vtstatus==VTSTTABS)
 {
  if(isshift) settabs();  
  else
  if(isctrl)  clearalltabs();
  else 
  {
   tabs[mttyx]=1;
   vtrefreshstatus();
  }
 }
}




/* double click with adjust */

void vtmarkcursortomouse(void)
{
 vtremzone();
 vtsetxy();

 if(((mttyy-tops)==24) && vtheight==25 && vtstatus!=VTSTHOST)
 {
  vtscleartab();
  return;
 }
 else
 {
  vtstartzone();
  paintzone(ttyx,ttyy+tops,1);
 }
}



/* double click with select in other words */

void vthomecursortomouse(void)
{
 int i;
 int xd;
 int yd;
 int dx;
 int dy;
 int y;
 int x;

 vtremzone();
 vtsetxy();

 y=mttyy-tops;
 x=mttyx;

 if(y<0 || y>23)
 {
  if(y==24) vtssettab();
  return;
 }


 xd=(x<ttyx);

 if(xd) dx=ttyx-x; 
 else   dx=x-ttyx;

 yd=(y<ttyy);

 if(yd) dy=ttyy-y; 
 else   dy=y-ttyy;

 for(i=0;i<dy;i++) vtintkey((0x18E)+yd);
 for(i=0;i<dx;i++) vtintkey((0x18D)-xd);
}




/* adjust in other words */

void vtsendreturn(void)
{
 vtsetxy();

 if(vtselect)
 {
  paintzone(mttyx,mttyy,1);
 }
 else
 {
  if((mttyy-tops)==24)
  {                        /* click on status line */
   vtscleartab();
   return;
  }
  vtintkey(CR);
 }
}



/* select in other words */

void vtsendcursorcode(void)
{
 int ch;

 tline * lp;
 int     loc;
 int   * data;

 if(vtselect)
 {
  clearzone();
  vtsetfocus();
 }
 else
 {
  vtsetxy();

  lp=vtindex(mttyy);

  if((mttyy-tops)==24)
  {                        /* click on status line */
   if(vtstatus==VTSTLOCAL) return;
   else
   if(vtstatus==VTSTTABS)
   {
    vtssettab();
    return;
   }
  }

  loc=lp->loc;

  data=(int *)(linedata+loc);

  ch=data[mttyx] & 0xFF;
  if(ch>=32) vtintkey(ch);
 }
}

